﻿using System;
using System.Windows;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ShinyWizard.Tests
{
    [TestClass]
    public class WizardControlTests
    {
        public static Style WizadDefaultStyle;

        [ClassInitialize]
        public static void ClassInitialize()
        {
            var dict = new ResourceDictionary
            {
                Source = new Uri("/ShinyWizard;component/Themes/WizardControlStyles.xaml", UriKind.Relative)
            };
            WizadDefaultStyle = (Style)dict[typeof(WizardControl)];
        }

        #region ActiveStep

        //[TestMethod]
        //[ExpectedException(typeof(ArgumentNullException))]
        //public void CannotSetNullActiveStep()
        //{
        //    // Arrange
        //    var wizard = new WizardControl();
        //    // Act
        //    wizard.ActiveStep = null;
        //    // Assert
        //}

        [TestMethod]
        public void NullActiveStepForEmptyStepsCollection()
        {
            // Arrange
            var wizard = new WizardControl();
            // Act
            // Assert
            Assert.IsNull(wizard.ActiveStep);
        }

        [TestMethod]
        public void NullActiveStepAfterStepsCollectionCleanup()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            wizard.Steps.Add(step1);
            // Act
            wizard.Steps.Clear();
            // Assert
            Assert.IsNull(wizard.ActiveStep);
        }

        [TestMethod]
        public void NotNullActiveStepAfterAddToStepsCollection()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            // Act
            wizard.Steps.Add(step1);
            // Assert
            Assert.IsNotNull(wizard.ActiveStep);
        }

        [TestMethod]
        public void UpdateActiveStepAfterInjection()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            // Act
            wizard.Steps.Add(step1);
            wizard.Steps.Insert(0, step2);
            // Assert
            Assert.IsTrue(ReferenceEquals(wizard.ActiveStep, step2));
        }

        #endregion

        #region FirstStep

        [TestMethod]
        public void NullFirstStepForEmptyStepsCollection()
        {
            // Arrange
            var wizard = new WizardControl();
            // Act
            // Assert
            Assert.IsNull(wizard.FirstStep);
        }

        [TestMethod]
        public void DetermineFirstStep()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            // Act
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            // Assert
            Assert.IsTrue(ReferenceEquals(wizard.FirstStep, step1));
        }

        [TestMethod]
        public void DetermineFirstStepAfterInjection()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            // Act
            wizard.Steps.Add(step1);
            wizard.Steps.Insert(0, step2);
            // Assert
            Assert.IsTrue(ReferenceEquals(wizard.FirstStep, step2));
        }

        #endregion

        #region Navigation Buttons

        [TestMethod]
        public void BackwardNavigation()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            // Act
            wizard.Style = WizadDefaultStyle;
            wizard.ApplyTemplate();
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            wizard.ActiveStep = step2;
            // Assert
            Assert.IsTrue(wizard.NavigateBackward());
            Assert.IsTrue(ReferenceEquals(wizard.ActiveStep, step1));
            Assert.IsFalse(wizard.BackButton.IsEnabled);
            Assert.IsTrue(wizard.NextButton.IsEnabled);
        }

        [TestMethod]
        public void SuppressBackwardNavigationWhenPreviousStepUnavaliable()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            // Act
            wizard.Style = WizadDefaultStyle;
            wizard.ApplyTemplate();
            wizard.Steps.Add(step1);
            // Assert
            Assert.IsFalse(wizard.NavigateBackward());
        }

        [TestMethod]
        public void UpdateNavigationButtonsAccessibilityWhenStepsCollectionChangedForOneStep()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            // Act
            wizard.Style = WizadDefaultStyle;
            wizard.ApplyTemplate();
            wizard.Steps.Add(step1);
            // Assert
            Assert.IsFalse(wizard.BackButton.IsEnabled);
            Assert.IsFalse(wizard.NextButton.IsEnabled);
        }

        [TestMethod]
        public void UpdateNavigationButtonsAccessibilityWhenStepsCollectionChangedForManySteps()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            // Act
            wizard.Style = WizadDefaultStyle;
            wizard.ApplyTemplate();
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            // Assert
            Assert.IsFalse(wizard.BackButton.IsEnabled);
            Assert.IsTrue(wizard.NextButton.IsEnabled);
        }

        [TestMethod]
        public void UpdateNavigationButtonsAccessibilityWhentActiveStepChangesToFirstStep()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            // Act
            wizard.Style = WizadDefaultStyle;
            wizard.ApplyTemplate();
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            wizard.ActiveStep = step1;
            // Assert
            Assert.IsFalse(wizard.BackButton.IsEnabled);
            Assert.IsTrue(wizard.NextButton.IsEnabled);
        }

        [TestMethod]
        public void UpdateNavigationButtonsAccessibilityWhentActiveStepChangesToLastStep()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            // Act
            wizard.Style = WizadDefaultStyle;
            wizard.ApplyTemplate();
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            wizard.ActiveStep = step2;
            // Assert
            Assert.IsTrue(wizard.BackButton.IsEnabled);
            Assert.IsFalse(wizard.NextButton.IsEnabled);
        }

        [TestMethod]
        public void ForwardNavigation()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            // Act
            wizard.Style = WizadDefaultStyle;
            wizard.ApplyTemplate();
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            // Assert
            Assert.IsTrue(wizard.NavigateForward());
            Assert.IsTrue(ReferenceEquals(wizard.ActiveStep, step2));
            Assert.IsTrue(wizard.BackButton.IsEnabled);
            Assert.IsFalse(wizard.NextButton.IsEnabled);
        }

        [TestMethod]
        public void SuppressForwardNavigationWhenNextStepUnavaliable()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            // Act
            wizard.Style = WizadDefaultStyle;
            wizard.ApplyTemplate();
            wizard.Steps.Add(step1);
            // Assert
            Assert.IsFalse(wizard.NavigateForward());
        }

        #endregion

        [TestMethod]
        public void NavigatingEventHanlingForForwardNavigation()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            var handled = false;
            // Act
            wizard.Navigating += (o, e) => handled = true;
            wizard.NavigateForward();
            // Assert
            Assert.IsTrue(handled);
        }

        [TestMethod]
        public void NavigatingEventHanlingForBackwardNavigation()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            wizard.ActiveStep = step2;
            var handled = false;
            // Act
            wizard.Navigating += (o, e) => handled = true;
            wizard.NavigateBackward();
            // Assert
            Assert.IsTrue(handled);
        }

        [TestMethod]
        public void NavigatedEventHanlingForForwardNavigation()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            var handled = false;
            // Act
            wizard.Navigated += (o, e) => handled = true;
            wizard.NavigateForward();
            // Assert
            Assert.IsTrue(handled);
        }

        [TestMethod]
        public void NavigatedEventHanlingForBackwardNavigation()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            wizard.ActiveStep = step2;
            var handled = false;
            // Act
            wizard.Navigated += (o, e) => handled = true;
            wizard.NavigateBackward();
            // Assert
            Assert.IsTrue(handled);
        }



        [TestMethod]
        public void CancelingNavigationForForwardNavigation()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            // Act
            wizard.Navigating += (o, e) => e.Cancel = true;
            wizard.NavigateForward();
            // Assert
            Assert.IsTrue(ReferenceEquals(wizard.ActiveStep, step1));
        }

        [TestMethod]
        public void CancelingNavigationForBackwardNavigation()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            wizard.ActiveStep = step2;
            // Act
            wizard.Navigating += (o, e) => e.Cancel = true;
            wizard.NavigateBackward();
            // Assert
            Assert.IsTrue(ReferenceEquals(wizard.ActiveStep, step2));
        }

        [TestMethod]
        public void UpdateStepsDataContextWhenDataContextChanged()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            var data = new object();
            // Act
            wizard.DataContext = data;
            // Assert
            Assert.IsTrue(ReferenceEquals(step1.DataContext, data));
            Assert.IsTrue(ReferenceEquals(step2.DataContext, data));
        }

        [TestMethod]
        public void SetDataContextForInjectedStep()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            var data = new object();
            // Act
            wizard.DataContext = data;
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            // Assert
            Assert.IsTrue(ReferenceEquals(step1.DataContext, data));
            Assert.IsTrue(ReferenceEquals(step2.DataContext, data));
        }

        [TestMethod]
        public void UpdateDataContextForReplacedSteps()
        {
            // Arrange
            var wizard = new WizardControl();
            var step1 = new WizardStep();
            var step2 = new WizardStep();
            var step3 = new WizardStep();
            var data = new object();
            wizard.DataContext = data;
            wizard.Steps.Add(step1);
            wizard.Steps.Add(step2);
            // Act
            wizard.Steps.Remove(step2);
            wizard.Steps[0] = step3;
            // Assert
            Assert.IsTrue(ReferenceEquals(step1.DataContext, data));
            Assert.IsTrue(ReferenceEquals(step2.DataContext, data));
            Assert.IsTrue(ReferenceEquals(step3.DataContext, data));
            Assert.AreEqual(wizard.Steps.Count, 1);
            Assert.IsFalse(wizard.Steps.Contains(step1));
            Assert.IsFalse(wizard.Steps.Contains(step2));
            Assert.IsTrue(wizard.Steps.Contains(step3));
        }

        [TestMethod]
        public void SetRoutedWizardNavigatorDataContext()
        {
            // Arrange
            var wizard = new WizardControl();
            var navigator = new RoutedWizardNavigator();
            var data = new object();
            wizard.DataContext = data;
            // Act
            wizard.Navigator = navigator;
            // Assert
            Assert.AreSame(navigator.DataContext, data);
        }

        [TestMethod]
        public void UpdateRoutedWizardNavigatorDataContext()
        {
            // Arrange
            var wizard = new WizardControl();
            var navigator = new RoutedWizardNavigator();
            var data = new object();
            wizard.Navigator = navigator;
            // Act
            wizard.DataContext = data;
            // Assert
            Assert.AreSame(navigator.DataContext, data);
        }
    }
}
